package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.context.FlowElementProcessContext;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.threadlocal.DeployIdContainer;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ThirdPlatformCallbackResolver;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserTaskActivityProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ExpressionUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowParticipantInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowVarExpressionVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.User;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.FlowUserTaskRoleInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowParticipantRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowUserTaskRoleInfoRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowVarExpressionRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.UserRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.common.impl.cfg.IdGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author lilh
 * @date 2020/11/17 11:20
 */
@Service
public class NonMultiInstanceUserTaskActivityProcessor implements UserTaskActivityProcessor {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private FlowVarExpressionRepository flowVarExpressionRepository;

    @Autowired
    private FlowParticipantRepository flowParticipantRepository;

    @Autowired
    private ThirdPlatformCallbackResolver resolver;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private FlowUserTaskRoleInfoRepository flowUserTaskRoleInfoRepository;

    @Override
    public boolean support(UserTask userTask) {
        return !userTask.hasMultiInstanceLoopCharacteristics();
    }

    @Override
    public void process(FlowElementProcessContext context) {
        UserTask userTask = (UserTask) context.getActivity();

        String assignee = userTask.getAssignee();

        //默认处理人都放在candidateUsers中，candidateGroups中无数据
        List<String> candidateUsers = userTask.getCandidateUsers();

        //如果都为空，则认为选择了留空
        if (StringUtils.isBlank(assignee) && CollectionUtils.isEmpty(candidateUsers)){
            List<String> candidateExpression = new ArrayList<>();
            candidateExpression.add("${flowUserTaskExpressionResolverServiceImpl.resolveCandidateUsers(execution)}");
            userTask.setCandidateUsers(candidateExpression);
        }else{

            userTask.setAssignee(null);
            Map<String,List<String>> expressionMap = new HashMap<>();
            for (String candidateUser : candidateUsers) {
                JSONObject jsonObject = JSONObject.parseObject(candidateUser);
                String type = jsonObject.getString("type");
                String value = jsonObject.getString("value");
                //不是变量类型
                if (!Objects.equals(type,"VAR")){
                    if (Objects.equals(type,"STA")){
                        userTask.addCustomUserIdentityLink(value,"STA");
                    }else if (Objects.equals(type,"RELATIONSHIP") || Objects.equals(type,"FUNCTION")){
                        addExpression(type,value,expressionMap);
                    }else{
                        userTask.addCustomGroupIdentityLink(value,type);
                    }
                }else{
                    String varType = jsonObject.getString("varType");
                    addExpression(varType,value,expressionMap);
                }
            }

            if (expressionMap.isEmpty()){
                userTask.setCandidateUsers(null);
            }else{
                List<String> candidateExpression = new ArrayList<>();
                candidateExpression.add("${flowUserTaskExpressionResolverServiceImpl.resolveCandidateUsers(execution)}");
                userTask.setCandidateUsers(candidateExpression);

                insertExpression(context.getDeployId(),context.getActivity().getId(),expressionMap);
            }
        }
    }

    private void addExpression(String type,String expression,Map<String,List<String>> expressionMap){
        List<String> expressionList = expressionMap.get(type);
        if (Objects.nonNull(expressionList) && !expressionList.isEmpty()){
            expressionList.add(expression);
        }else{
            expressionList = new ArrayList<>();
            expressionList.add(expression);
            expressionMap.put(type,expressionList);
        }
    }

    private void insertExpression(String deployId, String activityId, Map<String,List<String>> expressionMap) {
        List<FlowVarExpressionVo> flowVarExpressions = new ArrayList<>(expressionMap.size());

        Iterator<Map.Entry<String,List<String>>> iterator = expressionMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String,List<String>> expressionEntry = iterator.next();
            String type = expressionEntry.getKey();
            List<String> expressionList = expressionEntry.getValue();
            for (String expression : expressionList) {
                FlowVarExpressionVo flowVarExpression = new FlowVarExpressionVo();
                flowVarExpression.setDeployId(deployId);
                flowVarExpression.setActivityId(activityId);
                flowVarExpression.setExpression(expression);
                flowVarExpression.setType(type);
                flowVarExpression.setCreateTime(new Date());
                flowVarExpression.setUpdateTime(new Date());
                flowVarExpressions.add(flowVarExpression);
            }
        }

        flowVarExpressionRepository.insertBatch(flowVarExpressions);
    }

    private void resolveUserByRoles(List<String> roles, List<String> resolvedUsers) {
        for (String role : roles) {
            List<User> users = userRepository.listUserByRoleId(role);
            resolvedUsers.addAll(users.stream().map(User::getUserCode).collect(Collectors.toSet()));
        }
    }

    private List<String> resolveRoles(List<String> candidateGroups) {
        List<FlowParticipantInfoVo> participantInfos = flowParticipantRepository.listByParticipantIds(candidateGroups);
        List<FlowParticipantInfoVo> result = new ArrayList<>();
        for (FlowParticipantInfoVo entry : participantInfos) {
            if (Objects.equals(entry.getParticipantType(), "ROL")) {
                result.add(entry);
            }
        }
        if (CollectionUtils.isNotEmpty(result)) {
            return result.stream().map(FlowParticipantInfoVo::getParticipantId).collect(Collectors.toList());
        }
        return new ArrayList<>();

    }

    private boolean needResolveRole(JsonNode modelNode) {
        String modelId = null;
        JsonNode modelIdNode = modelNode.get("modelId");
        if (Objects.nonNull(modelIdNode) && modelIdNode instanceof TextNode) {
            modelId = modelIdNode.textValue();
        }

        String url = null;
        if (StringUtils.isNotEmpty(modelId)) {
            //根据modelId去查询
            url = resolver.resolveUrlByModelId(modelId);

        }
        return StringUtils.isEmpty(url);
    }

    private  void   saveUserTaskRoleInfo(String deployId, List<String> candidateUsers, List<String> roleIds, String nodeCode){
        if(roleIds!=null && roleIds.size()>0){
            String id = idGenerator.getNextId();
            FlowUserTaskRoleInfoVo flowUserTaskRoleInfoVo = new FlowUserTaskRoleInfoVo();
            flowUserTaskRoleInfoVo.setId(id);
            flowUserTaskRoleInfoVo.setDeployId(deployId);
            StringBuilder builder = new StringBuilder();
            for(String candidateUser: candidateUsers){
                builder.append(","+candidateUser);
            }
            String tmp = builder.toString();
            flowUserTaskRoleInfoVo.setCandidateUsers(StringUtils.isEmpty(tmp)? tmp:tmp.substring(1));
            builder = new StringBuilder();
            for(String roleId: roleIds){
                builder.append(","+roleId);
            }
            tmp = builder.toString();
            flowUserTaskRoleInfoVo.setRoleIds(StringUtils.isEmpty(tmp)? tmp:tmp.substring(1));
            flowUserTaskRoleInfoVo.setCreateTime(new Date());
            flowUserTaskRoleInfoVo.setUpdateTime(flowUserTaskRoleInfoVo.getCreateTime());
            flowUserTaskRoleInfoVo.setNodeCode(nodeCode);
            flowUserTaskRoleInfoRepository.insertUserTaskRoleInfo(flowUserTaskRoleInfoVo);
        }


    }
}
